﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Xml;
using System.Text;
using System.Windows.Forms;
using SdmxMl.Common;
using SdmxMl.Msg;
using SdmxMl.Manager;
using SdmxMl.Structure;

namespace SdmxMl.Panels
{
    public partial class DlgVariant : Form
    {
        #region Internal members

        private TreeSdmxManager treeSdmxManager;
        private DataTable worksheet;
        private int colDateInscr = 10;
        private int colDateRad = 13;

        #endregion

        #region Construction

        public DlgVariant(DataTable dtWorksheet, TreeSdmxManager tsMgr)
        {
            InitializeComponent();
            treeSdmxManager = tsMgr;
            worksheet = dtWorksheet;
        }
        #endregion

        private void buttonGenerate_Click(object sender, EventArgs e)
        {
            GenerateVariant(checkBoxUseCanton.Checked, 
                textBoxId.Text,
                Convert.ToInt32(textBoxColNo.Text) - 1, 
                Convert.ToDateTime(textBoxStartDate.Text));
        }

        /// <summary>
        /// Generate Variant Hierarchy according to variant column to use in Excel Worksheet
        /// </summary>
        /// <param name="placeCantonAsRoots">If True a first level with Cantons is created in hierarchy</param>
        /// <param name="variantId">The ID of the hierarchical variant artefact</param>
        /// <param name="colCode">variant column index to use in Excel Worksheet</param>
        /// <param name="startDate">Variant Hierarchy starting date</param>
        private void GenerateVariant(bool placeCanton, string variantId, int colCode, DateTime startDate)
        {
            // Create an Hierarchical Codelist artefact and it's container
            ArtefactManager armHierarchy = new ArtefactManager(SdmxArtefactType.HierarchicalCodelists);
            HierarchicalCodelistType he = new HierarchicalCodelistType();
            armHierarchy.ArtefactList.Add(he);

            // Now fill attributes of artefact
            he.Id = "HCL_" + variantId;
            he.AgencyId = "OFS";
            he.Version = "1.0";
            he.ValidFrom = startDate.ToString("yyyy-MM-dd");

            // Fetch name from column name in Excel Worksheet (2 lang same so written without specific language)
            string aName = worksheet.Rows[0][colCode].ToString();
            he.Name = new MultiLang(aName);

            // Create references to codelist used in heirarchy
            CodelistRefType clrefType = null;

            // Now ref to variant level codelist
            clrefType = new CodelistRefType(); 
            clrefType.AgencyId = "OFS";
            clrefType.Alias = "A";
            clrefType.Id = "CL_" + variantId;
            he.CodelistRefList.Add(clrefType);

            if (placeCanton)
            {
                clrefType = new CodelistRefType();
                clrefType.AgencyId = "OFS";
                clrefType.Alias = "KT";
                clrefType.Id = "CL_GDE_KT";
                he.CodelistRefList.Add(clrefType);
            }

            // Now ref to municipalities
            clrefType = new CodelistRefType();
            clrefType.AgencyId = "OFS";
            clrefType.Alias = "B";
            clrefType.Id = "CL_GDE_GDE";
            he.CodelistRefList.Add(clrefType);

            // Now the hierarchy
            HierarchyType heType = new HierarchyType(he.CodelistRefList);
            heType.Id = he.Id;
            heType.Name = he.Name.Clone();
            heType.Version = "1.0";
            he.HierarchyList.Clear();
            he.HierarchyList.Add(heType);

            // Dico for levels except municipalities
            Dictionary<string, CodeRefType> dicoCanton = GetCantonDico();
            Dictionary<string, CodeRefType> dicoRef = new Dictionary<string, CodeRefType>();

            string codeAId = null;
            string municipalityId = null;

            for (int row = 1; row < worksheet.Rows.Count; ++row)
            {
                // Get the ID's of municipality and variant level
                municipalityId = worksheet.Rows[row][0].ToString().Trim();
                if (municipalityId.Length == 0)
                    break;

                codeAId = worksheet.Rows[row][colCode].ToString().Trim();
                if (codeAId.Length > 0)
                {
                    bool doIt = true;
                    DateTime dtRadiate = DateTime.MinValue;
                    DateTime dtValidFrom = DateTime.FromOADate(Convert.ToDouble(worksheet.Rows[row][colDateInscr].ToString().Trim()));
                    if (dtValidFrom < startDate)
                        dtValidFrom = startDate;

                    // Get date radiation, if empty or bigger then start, create ref
                    string dateRadiateStr = worksheet.Rows[row][colDateRad].ToString().Trim();
                    if (dateRadiateStr.Length > 0)
                    {
                        dtRadiate = DateTime.FromOADate(Convert.ToDouble(dateRadiateStr));
                        // special case if create and radiate date are same, ignore also
                        if (dtRadiate < startDate)
                            doIt = false;
                    }
                    // This row is part of the hierarchy
                    if (doIt)
                    {
                        CodeRefType heRefcode = null;
                        // Already exist
                        if (dicoRef.ContainsKey(codeAId) == false)
                        {
                            heRefcode = new CodeRefType();
                            heRefcode.CodeID = codeAId;
                            heRefcode.CodelistAliasRef = "A";
                            dicoRef.Add(codeAId, heRefcode);
                        }
                        else
                            heRefcode = dicoRef[codeAId];

                        // do we need 
                        CodeRefType heRefCanton = null;
                        if (placeCanton)
                        {
                            string cantonAbbrev = worksheet.Rows[row][2].ToString().Trim();
                            // mettre dans heRefcode.CodeRefList si canton encore pas mis
                            heRefCanton = dicoCanton[cantonAbbrev];

                            if (heRefcode.CodeRefList.Contains(heRefCanton) == false)
                                heRefcode.CodeRefList.Add(heRefCanton);

                        }

                        // municipality ref
                        CodeRefType heRefChild = new CodeRefType();
                        heRefChild.CodeID = municipalityId;
                        heRefChild.CodelistAliasRef = "B";
                        heRefChild.ValidFrom = dtValidFrom.ToString("yyyy-MM-dd");
                        if (dtRadiate != DateTime.MinValue)
                            heRefChild.ValidTo = dtRadiate.ToString("yyyy-MM-dd");

                        if (placeCanton)
                            heRefCanton.CodeRefList.Add(heRefChild);
                        else
                            heRefcode.CodeRefList.Add(heRefChild);
                    }
                }
            }

            // Place constructed hierarchy in it's owner
            CodeRefCompareNum comparer = new CodeRefCompareNum();
            if (placeCanton)
            {
                foreach (KeyValuePair<string, CodeRefType> c in dicoRef)
                {
                    heType.CodeRefList.Add(c.Value);
                    c.Value.CodeRefList.Sort(comparer);
                }
                heType.CodeRefList.Sort(comparer);
            }
            else // start at variant level
            {
                foreach (KeyValuePair<string, CodeRefType> c in dicoRef)
                    heType.CodeRefList.Add(c.Value);
                heType.CodeRefList.Sort(comparer);
            }

            // Now persist created Hierarchycal codelist artefact
            WriteArtefact(armHierarchy, null, true);

        }

        /// <summary>
        /// In Excel there is an abbreviation of the canton, not it's code.
        /// So make a correspondance.
        /// </summary>
        /// <returns>corresp dictionary</returns>
        private Dictionary<string, CodeRefType> GetCantonDico()
        {
            Dictionary<string, CodeRefType> dicoRef = new Dictionary<string, CodeRefType>();

            dicoRef.Add("ZH", new CodeRefType("1", "KT"));
            dicoRef.Add("BE", new CodeRefType("2", "KT"));
            dicoRef.Add("LU", new CodeRefType("3", "KT"));
            dicoRef.Add("UR", new CodeRefType("4", "KT"));
            dicoRef.Add("SZ", new CodeRefType("5", "KT"));
            dicoRef.Add("OW", new CodeRefType("6", "KT"));
            dicoRef.Add("NW", new CodeRefType("7", "KT"));
            dicoRef.Add("GL", new CodeRefType("8", "KT"));
            dicoRef.Add("ZG", new CodeRefType("9", "KT"));
            dicoRef.Add("FR", new CodeRefType("10", "KT"));
            dicoRef.Add("SO", new CodeRefType("11", "KT"));
            dicoRef.Add("BS", new CodeRefType("12", "KT"));
            dicoRef.Add("BL", new CodeRefType("13", "KT"));
            dicoRef.Add("SH", new CodeRefType("14", "KT"));
            dicoRef.Add("AR", new CodeRefType("15", "KT"));
            dicoRef.Add("AI", new CodeRefType("16", "KT"));
            dicoRef.Add("SG", new CodeRefType("17", "KT"));
            dicoRef.Add("GR", new CodeRefType("18", "KT"));
            dicoRef.Add("AG", new CodeRefType("19", "KT"));
            dicoRef.Add("TG", new CodeRefType("20", "KT"));
            dicoRef.Add("TI", new CodeRefType("21", "KT"));
            dicoRef.Add("VD", new CodeRefType("22", "KT"));
            dicoRef.Add("VS", new CodeRefType("23", "KT"));
            dicoRef.Add("NE", new CodeRefType("24", "KT"));
            dicoRef.Add("GE", new CodeRefType("25", "KT"));
            dicoRef.Add("JU", new CodeRefType("26", "KT"));

            return dicoRef;
        }

        #region Artefact as SDMX File

        /// <summary> Write Artefact as SDMX Document </summary>
        /// <param name="arm">the artefact container</param>
        private void WriteArtefact(ArtefactManager arm, ArtefactManager armH, bool askForFile)
        {
            XmlTextWriter xw = null;
            string fileName = string.Empty;

            try
            {
                if (askForFile)
                {
                    saveFileDialog.Filter = "Sdmx files|*.xml|All Files|*.*";
                    saveFileDialog.FileName = arm.ArtefactList[0].Id;
                    if (saveFileDialog.ShowDialog() == DialogResult.OK &&
                        string.IsNullOrEmpty(saveFileDialog.FileName) == false)
                    {
                        fileName = saveFileDialog.FileName;
                    }
                }
                else
                {
                    // Use temp dir 
                    fileName = System.IO.Path.GetTempPath() + "SMS_SAE_temp.xml";

                }
                if (fileName.Length > 0)
                {

                    xw = new XmlTextWriter(fileName, Encoding.UTF8);
                    xw.Formatting = Formatting.Indented;
                    xw.WriteStartDocument();

                    HeaderGenerator.GetHeader().WriteXml(xw, HeaderType.ReferenceScheme.Structure);
                    arm.WriteXml(xw, null);

                    if (armH != null)
                        armH.WriteXml(xw, null);

                    xw.WriteEndDocument();
                    xw.Close();

                    if (treeSdmxManager != null)
                        treeSdmxManager.LoadSdmxArtefact(fileName, true, null);
                }
            }
            finally
            {
                if (xw != null)
                    xw.Close();
            }
        }

        #endregion // Artefact as SDMX File

    }
}
